#This contains the functions that do all the real work
import pygame, sys, os
from pygame.locals import *
import string
import random #Used to choose who starts, as well as randomly generate landscapes
import audio
sys.path.append('olpcgames')
import olpcgames
import tank

from olpcgames import pausescreen

class OLPCTanks:
    '''Class that handles everything about the game.'''
    def __init__(self, runaslib=True):
        '''Constructor. Parameter runaslib handles whether or not this is being run directly or
        by Sugar.'''
        self.therects = [] #Background rectangles
        self.theexplosions = [] #Explosion rectangles
        self.thetanks = [] #Tank sprites
        self.st = "Angle: 00 Power: 50" #Power/angle status string
        self.size = (800,600) #Screen size
        if olpcgames.ACTIVITY:
            self.size = olpcgames.ACTIVITY.game_size
        pygame.init()
        self.screen = pygame.display.set_mode(self.size) #Display surface
        self.clock = pygame.time.Clock() #Frame ticker
        if pygame.mixer.get_init() is not None: #If sound initialized, great!
            self.sound = audio.Audio()
        else:
            self.sound = audio.NoneSound() #Fake sound object
        self.init()
        self.main(runaslib)
        
        
    def init(self):
        '''Handles initialization of game objects.'''
        pygame.display.update()
        self.screen.fill((0,0,200)) #Background 'sky'
        self.draw_the_rectangles() #Land
        self.thetanks.append(tank.Tank()) #P1 sprite
        self.thetanks.append(tank.AITank()) #P2 sprite
        y = self.get_y_player(50)
        z = self.get_y_player(700)
        self.thetanks[0].rect.move_ip((50, y-self.thetanks[0].height)) #Put the sprites where they need to start
        self.thetanks[1].rect.move_ip((700, z-self.thetanks[1].height))
        self.turn = 0 #0 means human, 1 computer
        pygame.display.update()
        if pygame.font:
            font = pygame.font.Font(None, 36)
            self.text = font.render(self.st, 1, (10,10,10))
            self.textpos = self.text.get_rect(center=(self.screen.get_width()/2, self.screen.get_height()-50))
            self.screen.blit(self.text, self.textpos)
        self.sprites = pygame.sprite.RenderClear(self.thetanks[0], self.thetanks[1]) #Group the sprites so that they'll draw
        self.cross = tank.Crosshairs(self.thetanks[0].rect.topright[0], self.thetanks[0].rect.topright[1])
        self.hairs = pygame.sprite.RenderClear((self.cross))

    def main(self, runaslib = True):
        running = True
        self.sprites.draw(self.screen)
        self.hairs.draw(self.screen)
        while running:
            milliseconds = self.clock.tick(5) # maximum number of frames per second
            # Event-management loop with support for pausing after X seconds (25 here)
            events = pausescreen.get_events()
            # Now the main event-processing loop
            if events:
                for event in events:
                    if event.type == pygame.QUIT:
                        running = False
                    elif event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_ESCAPE:
                            running = False
                        if event.key == pygame.K_DOWN or event.key == pygame.K_KP2: #XO's arrow keys are numpad keys anyplace else
                            self.hairs.update(-1) #Angle goes down, so the crosshairs do too
                            font = pygame.font.Font(None, 36)
                            self.st = self.update_string(0, -1)
                            self.text = font.render(self.st, 1, (10,10,10))
                            self.textpos = self.text.get_rect(center=(self.screen.get_width()/2, self.screen.get_height()-50))
                        elif event.key == pygame.K_UP or event.key == pygame.K_KP8:
                            self.st = self.update_string(0, 1) #Angle goes up, so the crosshairs do too
                            font = pygame.font.Font(None, 36)
                            self.text = font.render(self.st, 1, (10,10,10))
                            self.textpos = self.text.get_rect(center=(self.screen.get_width()/2, self.screen.get_height()-50))
                            self.hairs.update(1)
                        elif event.key == pygame.K_LEFT or event.key == pygame.K_KP4:
                            self.st = self.update_string(1, -1)#Decreased power
                            font = pygame.font.Font(None, 36)
                            self.text = font.render(self.st, 1, (10,10,10))
                            self.textpos = self.text.get_rect(center=(self.screen.get_width()/2, self.screen.get_height()-50))
                        elif event.key == pygame.K_RIGHT or event.key == pygame.K_KP6:
                            self.st = self.update_string(1, 1)#Increased power
                            font = pygame.font.Font(None, 36)
                            self.text = font.render(self.st, 1, (10,10,10))
                            self.textpos = self.text.get_rect(center=(self.screen.get_width()/2, self.screen.get_height()-50))
                        elif event.key == pygame.K_SPACE:
                            self.shoot() #FIRE

            self.refresh(self.screen) #Draw everything again
            self.hairs.draw(self.screen)
            self.screen.blit(self.text, self.textpos)
            self.sprites.draw(self.screen)
            pygame.display.flip()

    def fire(self, power=0, angle=0):
        '''Fires a bullet from the tank using the power and angle in str'''
        bullet = tank.Cannonball(self.turn, self.thetanks[self.turn])
        words = string.split(self.st)
        if not power: #Computer passes power and angle, human pulls it from st
            bullet.power = int(words[3])
        else:
            bullet.power = power
        if not angle:
            bullet.angle = int(words[1])
        else:
            bullet.angle = angle
        bullet.do_physics() #Calculate Vx and Vy for the projectile
        return bullet

    def draw_the_rectangles(self):
        '''Draws a number rectangles of random height to make up the landscape'''
        random.seed()
        n = 6
        for i in range(n):
            height = random.randint(50, 500)
            w,h = self.screen.get_size()
            width = w/n
            rect = pygame.Rect(i*width, height, width, h-height)
            pygame.draw.rect(self.screen, (0, 135, 0), rect)
            self.therects.append(rect)
            
    def explode(self, screen, bullet):
        '''Shown when a shot explodes by drawing a 50x50 pixel rect.'''
        rect = bullet.rect
        rec = pygame.Rect(rect.topleft, (10, 10))
        pygame.draw.rect(self.screen, (0,0,200), rec)
        self.theexplosions.append(rec)
        
    def get_y_player(self, x):
        '''Gets the rectangle that contains the x value so that the players can go on top of them'''
        for rect in self.therects:
            if x in range(rect.left, rect.right):
                return rect.top

    def refresh(self, screen):
        '''Redraws the background'''
        self.screen.fill((0,0,200))
        for rect in self.therects:
            pygame.draw.rect(self.screen, (0,135, 0), rect)
        for rect in self.theexplosions:
            pygame.draw.rect(self.screen, (200,0,0), rect)
        
    def update_string(self, target, delta):
        '''Updates the string to reflect a change in power or angle or wins or losses'''
        arr = self.st.split()
        if (target == 0): #Angle changed
            val = int(arr[1])
            if (not (val <= 0 and delta < 0) and not (val >= 90 and delta > 0)):
                arr[1] = str(val + delta)
        elif (target == 1): #Power changed
            val = int(arr[3])
            if (not (val <= 0 and delta < 0) and not (val >= 100 and delta > 0)):
                arr[3] = str(val+5*delta)
        return string.join(arr, ' ')

    def has_exploded(self, bullet, turn, sound, screen):
        '''Checks if a bullet has hit a background rectangle or a tank''' 
        answer = False
        if (bullet.rect.collidelist(self.therects) != -1):
            answer = True
            bullet.dead = True
        if (bullet.rect.collidelist(self.theexplosions) != -1):
            answer = False
            bullet.dead = False
        if (bullet.rect.colliderect(self.thetanks[(turn+1)%2]) or self.thetanks[(turn+1)%2].rect.collidelist(self.theexplosions) != -1):
            answer = True
            bullet.dead = True
            self.win(turn, sound, screen)
        return answer
    
    def shoot(self, power=0, angle=0):
        '''Creates a bullet object, then shoots it from the tank, continuing to display it until it hits something or leaves the screen'''
        bullet = self.fire(power, angle)
        grp = pygame.sprite.RenderPlain((bullet))
        self.theexplosions = []
        while (1):
            grp.update(self.screen.get_width(), self.screen.get_height(), self.turn)
            self.refresh(self.screen)
            grp.draw(self.screen)
            self.sprites.draw(self.screen)
            pygame.display.flip()
            if (self.has_exploded(bullet, self.turn, self.sound, self.screen)):
                break
            elif bullet.dead:
                break
        self.explode(self.screen, bullet)
        grp.remove(bullet)
        del bullet

    def win(self, turn, sound, screen):
        '''Handles victory and reinitialization of the game board.'''
        self.sound.playWin(turn)
        screen = pygame.display.set_mode(self.size)
        self.screen.fill((0,0,200))
        self.sprites.clear(self.screen, screen)
        self.hairs.clear(self.screen, screen)
        self.screen = screen
        self.thetanks = []
        self.therects = []
        self.theexplosions = []
        self.thetanks.append(tank.Tank()) #P1 sprite
        self.thetanks.append(tank.AITank()) #P2 sprite
        self.draw_the_rectangles()
        y = self.get_y_player(50)
        z = self.get_y_player(700)
        self.thetanks[0].rect.move_ip((50, y-self.thetanks[0].height)) #Put the sprites where they need to start
        self.thetanks[1].rect.move_ip((700, z-self.thetanks[1].height))
        pygame.display.update()
        self.sprites = pygame.sprite.RenderClear(self.thetanks)
        self.cross = tank.Crosshairs(self.thetanks[0].rect.topright[0], self.thetanks[0].rect.topright[1])
        self.hairs = pygame.sprite.RenderClear(self.cross)
        self.st = "Angle: 00 Power: 50"
        
if __name__ == '__main__':
    OLPCTanks(False)